package com.example.testing.ipcdemo;


import android.annotation.TargetApi;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import com.squareup.okhttp.Call;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by josan_tang on 9/8/17.
 */

public class BookManagerService extends Service {
    private static final String TAG = "BMS";
    private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
    private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<IOnNewBookArrivedListener>();

    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();

    private Binder mBinder = new IBookManager.Stub() {
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            int check = checkCallingOrSelfPermission("com.example.testing.ipcdemo.permission.ACCESS_BOOK_SERVICE");
            if (check == PackageManager.PERMISSION_DENIED) {
                return false;
            }
            String packageName = "";
            String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
            if (packages != null && packages.length > 0) {
                packageName = packages[0];
            }
            if (!packageName.startsWith("com.example")) {
                return false;
            }

            return super.onTransact(code, data, reply, flags);
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            Log.e(TAG, "getBookList: ");
            //SystemClock.sleep(20000);
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }

        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        @Override
        public void registerLisenter(IOnNewBookArrivedListener listener) throws RemoteException {
            mListenerList.register(listener);
            Log.e(TAG, "registerLisenter,size:" + mListenerList.getRegisteredCallbackCount());
        }

        @Override
        public void unRegisterLisenter(IOnNewBookArrivedListener listener) throws RemoteException {
            mListenerList.unregister(listener);
            Log.e(TAG, "unRegisterLisenter,size:" + mListenerList.beginBroadcast());
        }


    };



    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate:");
        super.onCreate();
        mBookList.add(new Book(1, "Android"));
        mBookList.add(new Book(2, "IOS"));
        //测试Service中的主线程，不能直接访问网络
        // _getResponse("http://www.baidu.com/");
        new Thread(new ServiceWorker()).start();
    }

    /**
     * 得到OkHttpClient对象
     * @return
     */
    private static OkHttpClient getOkHttpClient() {
        OkHttpClient mOkHttpClient = new OkHttpClient();
        //设置OKHttpClient对象属性
        mOkHttpClient.setConnectTimeout(9000, TimeUnit.MILLISECONDS);
        mOkHttpClient.setReadTimeout(9000, TimeUnit.MILLISECONDS);
        return mOkHttpClient;
    }

    /***************** 底层的实现方法 ***************/

    /**
     * Get同步方式得到Response
     *
     * @param url
     *            请求url
     *
     * @return 请求结果Response
     */
    private static Response _getResponse(String url) {
        OkHttpClient mOkHttpClient = getOkHttpClient();

        // 创建Request
        final Request request = new Request.Builder().url(url).build();
        // 创建Call
        Call call = mOkHttpClient.newCall(request);
        try {
            // 发起请求，得到Response
            Response response = call.execute();
            return response;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        int check = checkCallingOrSelfPermission("com.example.testing.ipcdemo.permission.ACCESS_BOOK_SERVICE");
        Log.e(TAG, "onBind: check:" + check);
        if (check == PackageManager.PERMISSION_DENIED) {
            return null;
        }
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mIsServiceDestoryed.set(true);
    }

    /**
     * 新书通知
     * @param book
     * @throws RemoteException
     */
    private void onNewBookArrived(final Book book) throws RemoteException {
        mBookList.add(book);
        new Thread(new Runnable() {
            @Override
            public void run() {
                final int N = mListenerList.beginBroadcast();
                Log.e(TAG, "onNewBookArrived,notify listeners:" + N);
                Log.e(TAG, "onNewBookArrived: thread :" + Thread.currentThread().getName());
                for (int i = 0; i < N; i++) {
                    IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
                    if (listener != null) {
                        try {
                            listener.onNewBookArrived(book);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
                mListenerList.finishBroadcast();
            }
        }).start();
    }

    /**
     * 服务端任务
     */
    private class ServiceWorker implements Runnable {

        @Override
        public void run() {
            while (!mIsServiceDestoryed.get()) {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId = mBookList.size() + 1;
                Book newBook = new Book(bookId, "newBook#" + bookId);
                try {
                    onNewBookArrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
